package com.atguigu.tingshu.album.service.impl;

import com.atguigu.tingshu.album.mapper.TrackInfoMapper;
import com.atguigu.tingshu.album.service.AlbumInfoService;
import com.atguigu.tingshu.album.service.TrackInfoService;
import com.atguigu.tingshu.album.service.TrackStatService;
import com.atguigu.tingshu.album.service.VodService;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.result.ResultCodeEnum;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.model.album.TrackStat;
import com.atguigu.tingshu.model.user.UserInfo;
import com.atguigu.tingshu.query.album.TrackInfoQuery;
import com.atguigu.tingshu.user.client.UserInfoFeignClient;
import com.atguigu.tingshu.vo.album.AlbumTrackListVo;
import com.atguigu.tingshu.vo.album.TrackInfoVo;
import com.atguigu.tingshu.vo.album.TrackListVo;
import com.atguigu.tingshu.vo.album.TrackMediaInfoVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author sun
 */
@Slf4j
@Service
public class TrackInfoServiceImpl extends ServiceImpl<TrackInfoMapper, TrackInfo> implements TrackInfoService {

    @Resource
    private TrackInfoMapper trackInfoMapper;

    @Resource
    private VodService vodService;

    @Resource
    private AlbumInfoService albumInfoService;

    @Resource
    private TrackStatService trackStatService;

    @Resource
    private UserInfoFeignClient userInfoFeignClient;

    /**
     * 保存声音信息
     *
     * @param trackInfoVo 声音信息
     * @return 保存结果
     */
    @Override
    @Transactional
    public Integer saveTrackInfo(TrackInfoVo trackInfoVo) {

        TrackInfo trackInfo = new TrackInfo();
        BeanUtils.copyProperties(trackInfoVo, trackInfo);
        trackInfo.setUserId(AuthContextHolder.getUserId());
        // TODO 这里应该怎么设置？？
        trackInfo.setStatus(SystemConstant.TRACK_STATUS_NO_PASS);
        // 设置orderNum
        trackInfo.setOrderNum(trackInfoMapper.getLastTrackOrderNum(trackInfoVo.getAlbumId()));
        // 设置流媒体信息
        TrackMediaInfoVo trackMediaInfoVo = vodService.getTrackMediaInfo(trackInfo.getMediaFileId());
        trackInfo.setMediaDuration(new BigDecimal(trackMediaInfoVo.getDuration().toString()));
        trackInfo.setMediaSize(trackMediaInfoVo.getSize());
        trackInfo.setMediaType(trackMediaInfoVo.getType());
        trackInfo.setMediaUrl(trackMediaInfoVo.getMediaUrl());

        // 保存声音
        int result = trackInfoMapper.insert(trackInfo);

        // 更改专辑的声音信息 声音数量加一
        int trackCount = albumInfoService.getAlbumInfo(trackInfoVo.getAlbumId()).getIncludeTrackCount() + 1;

        albumInfoService.update(new LambdaUpdateWrapper<AlbumInfo>()
                .eq(AlbumInfo::getId, trackInfoVo.getAlbumId())
                .set(AlbumInfo::getIncludeTrackCount, trackCount)
        );
        // 设置声音的统计信息
        String[] statTypes = {
                SystemConstant.TRACK_STAT_PLAY,
                SystemConstant.TRACK_STAT_COLLECT,
                SystemConstant.TRACK_STAT_PRAISE,
                SystemConstant.TRACK_STAT_COMMENT
        };
        List<TrackStat> trackStats = Arrays.stream(statTypes).map(statType ->
                        TrackStat.builder()
                                .trackId(trackInfo.getId())
                                .statType(statType)
                                .statNum(0)
                                .build())
                .collect(Collectors.toList());
        trackStatService.saveBatch(trackStats);
        return result;
    }

    /**
     * 查询声音列表
     *
     * @param trackListVoPage 分页对象
     * @param trackInfoQuery  查询条件
     * @return 声音列表
     */
    @Override
    public IPage<TrackListVo> findUserTrackPage(Page<TrackListVo> trackListVoPage, TrackInfoQuery trackInfoQuery) {
        return trackInfoMapper.selectUserTrackPage(trackListVoPage, trackInfoQuery);
    }

    /**
     * 更新声音信息
     *
     * @param id          声音Id
     * @param trackInfoVo 声音Vo信息
     * @return 更新结果
     */
    @Override
    @Transactional
    public Integer updateTrack(Long id, TrackInfoVo trackInfoVo) {
        TrackInfo trackInfo = trackInfoMapper.selectById(id);
        if (trackInfo == null) {
            throw new GuiguException(ResultCodeEnum.TRACK_NOT_EXIST);
        }
        String mediaFileId = trackInfo.getMediaFileId();
        BeanUtils.copyProperties(trackInfoVo, trackInfo);
        if (!trackInfoVo.getMediaFileId().equals(mediaFileId)) {
            // 修改过声音信息
            TrackMediaInfoVo trackMediaInfo = vodService.getTrackMediaInfo(trackInfoVo.getMediaFileId());

            trackInfo.setMediaDuration(new BigDecimal(trackMediaInfo.getDuration().toString()));
            trackInfo.setMediaSize(trackMediaInfo.getSize());
            trackInfo.setMediaType(trackMediaInfo.getType());
            trackInfo.setMediaUrl(trackMediaInfo.getMediaUrl());
        }

        return trackInfoMapper.updateById(trackInfo);

    }

    /**
     * 删除声音
     *
     * @param id 声音Id
     * @return 删除结果
     */
    @Override
    @Transactional
    public Integer removeTrack(Long id) {
        TrackInfo trackInfo = trackInfoMapper.selectById(id);
        int result = trackInfoMapper.deleteById(id);
        //更新专辑总声音数
        Integer trackCount = albumInfoService.getOne(new LambdaQueryWrapper<AlbumInfo>()
                        .eq(AlbumInfo::getId, trackInfo.getAlbumId())
                        .select(AlbumInfo::getIncludeTrackCount))
                .getIncludeTrackCount();
        if (trackCount <= 0) {
            throw new GuiguException(ResultCodeEnum.TRACK_DELETE_ERROR);
        }
        albumInfoService.update(new LambdaUpdateWrapper<AlbumInfo>()
                .eq(AlbumInfo::getId, trackInfo.getAlbumId())
                .set(AlbumInfo::getIncludeTrackCount, trackCount - 1));
        //删除声音统计信息
        trackStatService.remove(new LambdaQueryWrapper<TrackStat>()
                .eq(TrackStat::getTrackId, id));
        //删除声音的媒体文件
        vodService.removeMediaFile(trackInfo.getMediaFileId());
        return result;
    }

    /**
     * 查询声音列表
     *
     * @param page    分页对象
     * @param albumId 专辑Id
     * @return 声音列表分页结果
     */
    @Override
    public IPage<AlbumTrackListVo> findAlbumTrackPage(Page<Object> page, Long albumId) {
        // 查询声音列表
        IPage<AlbumTrackListVo> pageInfo = trackInfoMapper.selectAlbumTrackPage(page, albumId);
        List<AlbumTrackListVo> tracks = pageInfo.getRecords();

        AlbumInfo albumInfo = albumInfoService.getById(albumId);

        Assert.notNull(albumInfo, "专辑不存在");

        Long userId = AuthContextHolder.getUserId();

        if (userId != null) {
            UserInfo userInfo = userInfoFeignClient.getUserInfoById(userId);
            Integer isVip = userInfo.getIsVip();
            Date vipExpireTime = userInfo.getVipExpireTime();
            if (isVip == 1 && vipExpireTime.after(new Date())) {
                // 是vip
                if (albumInfo.getPayType().equals(SystemConstant.ALBUM_PAY_TYPE_REQUIRE)) {
                    // 付费专辑
                    setIsShowPaidMark(albumId, tracks, albumInfo, userId);
                }
            } else {
                // 不是vip
                if (!albumInfo.getPayType().equals(SystemConstant.ALBUM_PAY_TYPE_FREE)) {
                    // 不是免费专辑
                    setIsShowPaidMark(albumId, tracks, albumInfo, userId);

                }
            }
        }else {
            // 未登录  ---> 只能看前15个声音
            if (albumInfo.getPayType().equals(SystemConstant.ALBUM_PAY_TYPE_FREE)) {
                // 免费专辑 15 集
                tracks.stream()
                        .filter(track -> track.getOrderNum() > 15)
                        .forEach(track -> track.setIsShowPaidMark(true));
            } else {
                // 付费专辑 5 集
                tracks.stream()
                        .filter(track -> track.getOrderNum() > 5)
                        .forEach(track -> track.setIsShowPaidMark(true));
            }
        }
        pageInfo.setRecords(tracks);
        return pageInfo;
    }


    /**
     * 设置付费标识
     * @param albumId 专辑id
     * @param tracks 声音列表
     * @param albumInfo 专辑信息
     * @param userId 用户id
     */
    private void setIsShowPaidMark(Long albumId, List<AlbumTrackListVo> tracks, AlbumInfo albumInfo, Long userId) {
        tracks.stream()
                // 前5集设为免费
                .filter(track -> track.getOrderNum() > 5)
                // 设置付费标识
                .forEach(track -> track.setIsShowPaidMark(true));
        if (albumInfo.getPriceType().equals(SystemConstant.ALBUM_PRICE_TYPE_ALL)) {
            // 整张专辑购买
            if (userInfoFeignClient.isPaidAlbum(albumId)) {
                // 购买过专辑
                tracks.forEach(track -> track.setIsShowPaidMark(false));
            }
        }else {
            // 单个声音购买
            HashSet<Long> ids = userInfoFeignClient.getPaidTrackIds(albumId, userId);
            if (!ids.isEmpty()) {
                tracks.stream()
                        .filter(track -> ids.contains(track.getTrackId()))
                        .forEach(track -> track.setIsShowPaidMark(false));
            }
        }
    }



    /**
     * 查询用户可以购买的声音
     *
     * @param trackId 声音Id
     * @return 用户可以购买的声音
     */
    @Override
    public List<Map<String,Object>> findUserTrackPaidList(Long trackId) {

        ArrayList<Map<String, Object>> result = new ArrayList<>();
        TrackInfo trackInfo = getById(trackId);
        if (trackInfo == null) {
            throw new GuiguException(ResultCodeEnum.TRACK_NOT_EXIST);
        }
        AlbumInfo albumInfo = albumInfoService.getById(trackInfo.getAlbumId());
        if(albumInfo == null){
            throw new GuiguException(ResultCodeEnum.ALBUM_NOT_EXIST);
        }else if (albumInfo.getPayType().equals(SystemConstant.ALBUM_PAY_TYPE_FREE)){
            throw new GuiguException(ResultCodeEnum.ALBUM_FREE);
        }

        HashMap<String, Object> map = new HashMap<>();
        map.put("name","本集");
        map.put("price",albumInfo.getPrice());
        map.put("trackCount",1);
        result.add(map);

        // 查询当前声音及以后所有的声音 并 过滤用户已经购买的声音
        List<TrackInfo> trackInfos = trackInfoMapper.selectList(new LambdaQueryWrapper<TrackInfo>()
                .ge(TrackInfo::getOrderNum, trackInfo.getOrderNum())
                .eq(TrackInfo::getAlbumId, trackInfo.getAlbumId()));
        HashSet<Long> ids = userInfoFeignClient.getPaidTrackIds(trackInfo.getAlbumId(), AuthContextHolder.getUserId());
        trackInfos = trackInfos.stream()
                .filter(track -> !ids.contains(track.getId()))
                .limit(50)
                .toList();
        int size = trackInfos.size();
        if (size == 1){
            return result;
        }
        // 拼装返回结果
        for (int i = 1; i <= (size % 10 == 0 ? size/10 : size/10 + 1); i++) {
            map = new HashMap<>();
            int num = Math.min(i * 10, size);
            BigDecimal price = albumInfo.getPrice().multiply(new BigDecimal(num));
            map.put("name","后"+num+"集");
            map.put("price",price);
            map.put("trackCount",num);
            result.add(map);
        }
        return result;
    }

    /**
     * 根据专辑id查询声音信息
     *
     * @param albumId    专辑id
     * @param orderNum   声音排序
     * @param trackCount 声音数量
     * @return 声音信息集合
     */
    @Override
    public List<TrackInfo> getTrackInfoList(Long albumId, Integer orderNum, Integer trackCount) {
        List<TrackInfo> trackInfos = trackInfoMapper.selectList(
                new LambdaQueryWrapper<TrackInfo>()
                        .ge(TrackInfo::getOrderNum, orderNum)
                        .eq(TrackInfo::getAlbumId, albumId)
        );
        HashSet<Long> ids = userInfoFeignClient.getPaidTrackIds(albumId, AuthContextHolder.getUserId());
        if (!CollectionUtils.isEmpty(ids)) {
            // 过滤用户已购买的声音
            return trackInfos.stream()
                    .filter(track -> !ids.contains(track.getId()))
                    .limit(trackCount)
                    .toList();
        }
        return trackInfos.stream().limit(trackCount).toList();
    }


}
